<?php

namespace ltcms\container;

/**
 * 容器基类
 */
class ContainerBase implements \ArrayAccess
{
    private static $_instance;
    protected $_instances;
    protected $bind=array();

    private function __construct(){}
    private function __clone(){ }

    /**
     * 获取类对象
     */
    public static  function getInstance(){
        if(!(self::$_instance instanceof self)){
            self::$_instance=new self();
        }
        return self::$_instance;
    }

    /**
     * 检测是否存在
     * @param mixed $offset
     * @return bool
     */
    public function offsetExists($offset){
        return isset($this->bind[$offset]);
    }

    /**
     * 获取容器
     * @param mixed $offset
     * @return bool|mixed
     */
    public function offsetGet($offset){
        if($this->offsetExists($offset)){
            return $this->bind[$offset];
        }else{
            return null;
        }
    }

    /**
     * 设置容器
     * @param mixed $offset
     * @param mixed $value
     * return void
     */
    public function offsetSet($offset, $value){
        $this->bind[$offset] = $value;
    }

    /**
     * 删除容器
     * @param mixed $offset
     */
    public function offsetUnset($offset){
        if($this->offsetExists($offset)){
            unset($this->bind[$offset]);
        }
    }

    /**
     * 绑定容器
     * @param mixed $offset
     */
    public function bind($abstract, $concrete = null){
        if (is_array($abstract)) {
            foreach ($abstract as $key => $val) {
                $this->bind($key, $val);
            }
        } elseif ($concrete instanceof \Closure) {
            $this->bind[$abstract] = $concrete;
        }else{
            $this->bind[$abstract] = $concrete;
        }
        return $this;
    }

    /**
     * 创建类的实例 已经存在则直接获取
     * @param $abstract
     * @param array $vars
     * @param bool $newInstance
     * @return bool
     */
    public function make($abstract, array $vars = [], $newInstance = false)
    {
        if (isset($this->_instances[$abstract]) && !$newInstance) {
            return $this->_instances[$abstract];
        }
        if (isset($this->bind[$abstract])) {
            $classNamespace=$this->bind[$abstract];
            if(class_exists($classNamespace)){
                $object = new $classNamespace();
                if (!$newInstance) {
                    $this->_instances[$abstract] = $object;
                }
                return $object;
            }else{
                throw new \RuntimeException('class not find: ' . $classNamespace);
            }
        }else if(class_exists($abstract)){
            $object = new $abstract();
            if (!$newInstance) {
                $this->_instances[$abstract] = $object;
            }
            return $object;
        }else{
            throw new \RuntimeException('class not find: ' . $abstract);
        }
    }
}